home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SGI Freeware 1998 June
/
SGI Freeware 1998 June.iso
/
dist
/
fw_UMINNgopher.idb
/
usr
/
freeware
/
src
/
gopher_1.12
/
gopher
/
CURcurses.c.z
/
CURcurses.c
Wrap
C/C++ Source or Header
|
1997-09-09
|
21KB
|
1,031 lines
/********************************************************************
* $Author: drich $
* $Revision: 1.1 $
* $Date: 1995/10/03 04:07:54 $
* $Source: /proj/freeware1.0/gopher1.12/src/gopher/RCS/CURcurses.c,v $
* $State: Exp $
*
* Paul Lindner, University of Minnesota CIS.
*
* Copyright 1991, 1992 by the Regents of the University of Minnesota
* see the file "Copyright" in the distribution for conditions of use.
*********************************************************************
* MODULE: CURcurses.c
* Abstraction of all Curses Functions
*********************************************************************
* Revision History:
* $Log: CURcurses.c,v $
* Revision 1.1 1995/10/03 04:07:54 drich
* gopher 1.2 check-in
*
* Revision 1.8 1993/01/11 20:25:31 lindner
* Fixed weird wprintw error on EP/IX.
*
* Revision 1.7 1993/01/09 02:16:21 lindner
* Changed (void*)-1 constructs to SIG_ERR
*
* Revision 1.6 1993/01/09 01:28:11 lindner
* Replaced hosed Log messages (Ooops!)
*
* Revision 1.5 1993/01/09 01:24:42 lindner
* Added CURchoice(), let's you choose one option from [2-9] items.
*
* Revision 1.4 1993/01/09 00:49:16 lindner
* More mods for VMS from jqj. Looks like better ctrl-y and ctrl-c
* processing.
*
* Revision 1.3 1993/01/06 17:05:46 lindner
* Added nl() to CURexit() for EP/IX machines.
*
* Revision 1.2 1992/12/31 05:55:44 lindner
* Mods for VMS
*
* Revision 1.1 1992/12/10 06:16:51 lindner
* Initial revision
*
*
*********************************************************************/
#include "CURcurses.h"
#include "Malloc.h"
#include <signal.h>
#include "Stdlib.h"
#include "compatible.h"
#ifdef VMS
void setterm_pas();
void resetterm();
static int w_getch();
#define wgetch w_getch
#endif
/*
* Initialize data space for various screen information
*/
CursesObj *
CURnew()
{
CursesObj *cur;
cur = (CursesObj *) malloc(sizeof(CursesObj));
cur->Screen = NULL;
cur->Termtype = STRnew();
cur->Clearscreen = STRnew();
cur->AudibleBell = STRnew();
cur->Highlighton = STRnew();
cur->Highlightoff = STRnew();
cur->inCurses = FALSE;
cur->sigtstp = (void*)-1;
cur->sigwinch = (void*)-1;
CURinit(cur);
return(cur);
}
/*
* Initialize various strings and such.
*/
void
CURinit(cur)
CursesObj *cur;
{
int err;
static char terminal[1024];
static char capabilities[1024]; /* String for cursor motion */
static char *ptr = capabilities; /* for buffering */
char *cp;
#ifdef VMS
CURsetTerm(cur, "VMS");
CURsetBell(cur, "\007");
CURsetCLS(cur, "");
CURsetHighon(cur, "");
CURsetHighoff(cur, "");
#else
/*** Set the terminal type ***/
if (getenv("TERM") != NULL)
CURsetTerm(cur, getenv("TERM"));
else
CURsetTerm(cur, "unknown");
err = tgetent(terminal, CURgetTerm(cur));
if (err !=1)
CURsetTerm(cur, "unknown");
/*** Get the clearscreen code ***/
if ((cp = (char *)tgetstr("cl", &ptr)) != NULL)
CURsetCLS(cur, cp);
else
CURsetCLS(cur, "");
/*** Set the bell ***/
if ((cp = (char *) tgetstr("bl", &ptr)) != NULL)
CURsetBell(cur, cp);
else
CURsetBell(cur, "\007");
/*** Set the highlight codes ***/
if ((cp = (char *) tgetstr("so", &ptr)) != NULL) {
CURsetHighon(cur, cp);
if ((cp = (char *) tgetstr("se", &ptr)) != NULL)
CURsetHighoff(cur, cp);
} else {
CURsetHighon(cur, "");
CURsetHighoff(cur, "");
}
CURsetScreen(cur,initscr());
#endif
cur->inCurses = FALSE;
}
/*
* Given a properly "CURnew" cursesobj, initialize the screen..
*/
void
CURenter(cur)
CursesObj *cur;
{
/* for safety */
if (cur->inCurses == TRUE)
return;
#ifdef VMS
(void)setterm_pas();
CURsetScreen(cur,initscr());
#else
tputs(CURgetCLS(cur),1,CURoutchar);
fflush(stdout);
#endif
cur->inCurses = TRUE;
CURwenter(cur,stdscr);
#ifdef SIGWINCH
if (cur->sigwinch != SIG_ERR)
signal(SIGWINCH, cur->sigwinch);
#endif
#ifndef VMS
if (cur->sigtstp != SIG_ERR)
signal(SIGTSTP, cur->sigtstp);
#endif
}
/*
* Set up processing for the window (especially for system V curses!
*/
void
CURwenter(cur, win)
CursesObj *cur;
WINDOW *win;
{
cbreak();
noecho();
nonl();
#ifdef SYSVCURSES
intrflush(win, FALSE);
nodelay(win, FALSE);
#ifndef ultrix /** Causes wgetch to dump core in ultrix **/
keypad(win, TRUE);
#endif
#endif
}
/*
* Exit curses system.
*/
void
CURexit(cur)
CursesObj *cur;
{
if (!cur->inCurses)
return;
cur->inCurses = FALSE;
echo();
nl();
endwin();
#ifdef SYSVCURSES
keypad(stdscr, FALSE);
#endif
#ifdef VMS
(void)resetterm();
#else
tputs(CURgetCLS(cur),1,CURoutchar);
fflush(stdout);
cur->sigtstp = signal(SIGTSTP, SIG_DFL);
#endif
#ifdef SIGWINCH
cur->sigwinch = signal(SIGWINCH, SIG_DFL);
#endif
}
/*
* send a character to stdout, not really curses, but we do use it...
*/
int
CURoutchar(c)
char c;
{
/** output the given character. From tputs... **/
/** Note: this CANNOT be a macro! **/
putc(c, stdout);
return(c);
}
/*
* Centerline, uses curses routines to center a line.
*/
void CURcenterline(cur, theline, yval)
CursesObj *cur;
char *theline;
int yval;
{
mvaddstr(yval, (COLS - strlen(theline))/2, theline);
}
/*
* CURwgetstr is a replacement of getstr that allows editing of the string
*
* if the user types control codes we don't recognize, it's returned instead
*
* We assume that the incoming string is shorter than the max..
*
*/
int
CURwgetstr(cur, win, inputline, maxlength)
CursesObj *cur;
WINDOW *win;
char *inputline;
int maxlength;
{
int pointer = 0;
int curpointer = 0;
int ch;
int y,x;
CURwenter(cur, win);
cbreak();
noecho();
wstandout(win);
/*** Check to see if there's something in the inputline already ***/
while (inputline[pointer] != '\0') {
waddch(win, inputline[pointer]);
pointer ++;
curpointer ++;
}
wrefresh(win);
for (;;) {
ch = CURwgetch(cur,win);
switch (ch) {
case '\n':
inputline[pointer] = '\0';
return(ch);
break;
/** Backspace and delete **/
case '\b':
if (curpointer > 0) {
char *cp;
getyx(win, y,x);
wmove(win, y, x-1);
/** Update the string **/
for (cp = inputline +curpointer-1; *cp != '\0'; cp++) {
*cp = *(cp+1);
if (*cp != '\0') waddch(win, *cp);
}
*cp = '\0';
waddch(win, ' ');
waddch(win, ' ');
pointer--;
curpointer--;
wmove(win, y, x-1);
wrefresh(win);
} else
CURBeep(cur);
break;
case '\007': /*** ^G cancel... ***/
CURBeep(cur);
wstandend(win);
return(-1);
break;
/*** Kill character (ctrl-u) ***/
case '\025':
while (pointer!=0) {
waddch(win,'\010');
waddch(win, ' ');
waddch(win, '\010');
inputline[--pointer] = '\0';
curpointer = 0;
}
wrefresh(win);
break;
case KEY_LEFT:
if (curpointer > 0) {
curpointer--;
getyx(win, y, x);
wmove(win, y, x-1);
wrefresh(win);
}
break;
case KEY_RIGHT:
if (curpointer<pointer) {
int y,x;
curpointer++;
getyx(win, y, x);
wmove(win, y, x+1);
wrefresh(win);
}
break;
default:
if (isprint(ch) && curpointer == maxlength) {
CURBeep(cur);
}
else if (isprint(ch)) {
inputline[curpointer++] = ch;
if (curpointer > pointer) {
pointer = curpointer;
inputline[curpointer+1] = '\0';
}
waddch(win, ch);
wrefresh(win);
}
else {
wstandend(win);
return(ch);
}
}
}
}
/*
* This stuff is stolen and modified from hytelnet Thanks Earl!
*/
int
CURwgetch(cur, window)
CursesObj *cur;
WINDOW *window;
{
int a, b, c;
c = wgetch(window);
if (c == 27) { /* handle escape sequence */
b = wgetch(window);
if (b == '[' || b == 'O')
a = wgetch(window);
else
a = b;
switch (a) {
case 'A': c = KEY_UP; break;
case 'B': c = KEY_DOWN; break;
case 'C': c = KEY_RIGHT; break;
case 'D': c = KEY_LEFT; break;
case '5': /* vt 300 prev. screen */
if (b == '[' && wgetch(window) == '~')
c = KEY_PPAGE;
break;
case '6': /* vt 300 next screen */
if (b == '[' && wgetch(window) == '~')
c = KEY_NPAGE;
break;
}
}
/* The many forms of the return key... */
if ((c == KEY_ENTER)|| (c=='\r'))
c = '\n'; /** SYSV curses Gack! **/
/* The many forms of backspace */
if (c == '\010' || c == '\177' || c == KEY_BACKSPACE)
return('\b');
return(c);
}
int
CURgetch(cur)
CursesObj *cur;
{
return(CURwgetch(cur, stdscr));
}
/*
* Resets the screen when a size change has happened
*/
void
CURresize(cur)
CursesObj *cur;
{
if (cur->inCurses) {
CURexit(cur);
CURsetScreen(cur, initscr());
CURenter(cur);
}
}
/*
* Get one option displays a message, and gets a response
*
* If the Response has something in it, it is displayed and editable
*
* If the user wants to abort, GetOneOption returns a -1, otherwise it
* returns a 0
*/
int
CURGetOneOption(cur, OptionName, Response)
CursesObj *cur;
char *OptionName, *Response;
{
int i;
char *message[2];
char *response[2];
message[0] = OptionName;
message[1] = NULL;
response[0] = Response;
response[1] = NULL;
i = CURRequest(cur, NULL, message, response);
refresh();
return(i);
}
/*
* This is the old version of GetOneOption, for those times when the
* garsh darn terminal is just too gadblam slow :-)
*/
int
CUROldGetOneOption(cur, OptionName, Response)
CursesObj *cur;
char *OptionName, *Response;
{
int i;
mvaddstr(LINES-1, 0, OptionName);
standout();
addstr(" ");
standend();
clrtoeol();
move(LINES-1, strlen(OptionName));
refresh();
echo();
i = CURwgetstr(cur, stdscr, Response, 4);
noecho();
return(i);
}
/*
* Fills in the Response with either a lowercase 'y' or 'n'
*/
void
CURgetYesorNo(cur, OptionName, Response)
CursesObj *cur;
char *OptionName, *Response;
{
int c;
int posx, posy;
mvaddstr(LINES-1, 0, OptionName);
clrtoeol();
noecho();
getyx(cur->Screen, posy, posx);
addch(' ');
if (*Response == 'y')
mvaddstr(posy, posx+1, "y");
else {
*Response = 'n';
mvaddstr(posy, posx+1, "n ");
}
move(posy, posx+1);
refresh();
while (1) {
c = CURgetch(cur);
if (c == 'y') {
mvaddstr(posy, posx+1, "Yes");
move(posy, posx+1);
refresh();
*Response = 'y';
*(Response +1) = '\0';
return;
}
else if (c == 'n') {
mvaddstr(posy, posx+1, "No ");
move(posy, posx+1);
refresh();
*Response = 'n';
*(Response +1) = '\0';
return;
}
else if ((c == '\n')||(c=='\r')) {
return;
}
#ifdef VMS
else if ( c == '\032' ) { /* control-Z */
return;
}
#endif
else {
CURBeep(cur);
}
}
}
void
CURBeep(cur)
CursesObj *cur;
{
#ifdef SYSVCURSES
beep();
#else
CURcenterline(cur,CURgetBell(cur),1);
/* tputs(CURgetBell(cur),1,CURoutchar); */
/* fflush(stdout); */
#endif
}
void
CURbox(cur, win, height,width)
CursesObj *cur;
WINDOW *win;
int width, height;
{
int i;
wmove(win,0,0);
#ifdef SYSVCURSES
wattron(win, A_ALTCHARSET);
#endif
waddch(win, BOX_UL);
for (i=0; i<width-2; i++)
waddch(win, BOX_HLINE);
waddch(win, BOX_UR);
for (i=1; i<height-1; i++) {
wmove(win, i,0);
waddch(win, BOX_VLINE);
wmove(win, i,width-1);
waddch(win, BOX_VLINE);
}
wmove(win, height-1,0);
waddch(win, BOX_LL);
for (i=0; i<width-2; i++)
waddch(win, BOX_HLINE);
waddch(win, BOX_LR);
#ifdef SYSVCURSES
wattroff(win, A_ALTCHARSET);
#endif
}
void
CURbutton(cur, win, Label, bright)
CursesObj *cur;
WINDOW *win;
char *Label;
boolean bright;
{
#ifdef SYSVCURSES
wattron(win, A_BOLD);
#endif
if (bright)
wstandout(win);
waddstr(win, "[");
waddstr(win, Label);
waddstr(win, "]");
if (bright)
wstandend(win);
#ifdef SYSVCURSES
wattroff(win, A_BOLD);
#endif
}
int
CURDialog(cur, Wintitle, Message)
CursesObj *cur;
char **Message;
char *Wintitle;
{
WINDOW *tempwin;
int i,messlength=25, winwidth;
int messheight=0;
while (Message[messheight] != NULL) {
if (strlen(Message[messheight]) > messlength)
messlength = strlen(Message[messheight]);
messheight++;
}
if (messlength > COLS)
messlength = COLS -4;
if (strlen(Wintitle) > messlength)
winwidth = strlen(Wintitle) + 2;
winwidth = messlength + 6;
if (winwidth < 30)
winwidth = 30;
tempwin = newwin(6+messheight, winwidth, (LINES-(6+messheight))/2, (COLS-winwidth) /2);
CURwenter(cur,tempwin);
CURbox(cur, tempwin, 6+messheight, winwidth);
/** Add the message **/
for (i=0; i<messheight; i++) {
wmove(tempwin, 2+i,(winwidth - messlength)/2);
waddstr(tempwin, Message[i]);
}
/** Add the window title **/
if (Wintitle != NULL) {
wmove(tempwin, 0,(winwidth - strlen(Wintitle))/2);
wstandout(tempwin);
waddstr(tempwin, Wintitle);
wstandend(tempwin);
}
/** Add the keyboard labels **/
wmove(tempwin, 3+messheight, winwidth - 29);
CURbutton(cur, tempwin, "Cancel - ^G", FALSE);
waddch(tempwin, ' ');
CURbutton(cur, tempwin, "OK - Enter", FALSE);
wrefresh(tempwin);
switch(CURwgetch(cur, tempwin)) {
case -1:
case '\007':
delwin(tempwin);
return(-1);
default:
delwin(tempwin);
return(0);
}
}
int
CURRequest(cur,Wintitle,Prompts,Stowages)
CursesObj *cur;
char *Wintitle;
char **Prompts;
char **Stowages;
{
WINDOW *tempwin;
int i,j;
int numprompts=0;
int maxpromptwidth =0;
int currentfield = 0;
/** Find the number of prompts... and the max width***/
while (Prompts[numprompts++] != NULL)
if (strlen(Prompts[numprompts-1]) > maxpromptwidth)
maxpromptwidth = strlen(Prompts[numprompts-1]);
numprompts --;
if (numprompts == 0) {
return(-1);
}
tempwin = newwin(6 + numprompts, COLS-2, (LINES-(6+numprompts))/2,1);
CURwenter(cur,tempwin);
CURbox(cur,tempwin, 6+numprompts, COLS-2);
/*** Add the window title ***/
if (Wintitle != NULL) {
wmove(tempwin, 0,(COLS -2 - strlen(Wintitle))/2);
wstandout(tempwin);
waddstr(tempwin, Wintitle);
wstandend(tempwin);
}
/** Add the prompts and typing area **/
for (i=0; i <numprompts; i++) {
wmove(tempwin, 2+i, 2);
waddstr(tempwin, Prompts[i]);
/** Add the black space for the stowage, and the stowage, if it
exists **/
wmove(tempwin, 2+i, maxpromptwidth +4);
wstandout(tempwin);
waddstr(tempwin, Stowages[i]);
for (j=strlen(Stowages[i])+maxpromptwidth+4; j< COLS-6; j++) {
waddch(tempwin, ' ');
}
wstandend(tempwin);
}
/** Add the labels **/
if (numprompts > 1) {
wmove(tempwin, 3+numprompts, 3);
CURbutton(cur, tempwin, "Switch Fields - TAB", FALSE);
}
wmove(tempwin, 3+numprompts, COLS/2);
CURbutton(cur, tempwin, "Cancel ^G", FALSE);
waddch(tempwin, ' ');
CURbutton(cur, tempwin, "Accept - Enter", FALSE);
while (1) {
wmove(tempwin, 2+currentfield, maxpromptwidth +4);
wrefresh(tempwin);
switch (CURwgetstr(cur,tempwin,Stowages[currentfield],80)) {
case '\t':
case KEY_DOWN:
/*** Move to another field ***/
currentfield = (currentfield +1) % numprompts;
break;
case KEY_UP:
currentfield--;
if (currentfield <0)
currentfield = numprompts-1;
break;
case '\007':
case -1:
/*** Cancel ***/
delwin(tempwin);
return(-1);
case '\n':
delwin(tempwin);
return(0);
}
}
}
/*
* CURChoice takes a bunch of titles, throws them on the screen,
* and asks the user to choose one.
*
* Returns the number chosen, or -1 if the user cancels.
*/
int
CURChoice(cur, Wintitle, choices, prompt)
CursesObj *cur;
char *Wintitle;
char **choices;
char *prompt;
{
int numchoices=0, i, maxchoicewidth=0;
WINDOW *tempwin;
while (choices[numchoices++] != NULL)
if ((i=strlen(choices[numchoices-1])) > maxchoicewidth)
maxchoicewidth = i;
numchoices--;
if (numchoices == 0)
return(-1);
if ((i=strlen(prompt)) > maxchoicewidth)
maxchoicewidth = i;
if ((i=strlen(Wintitle)) > maxchoicewidth)
maxchoicewidth = i;
tempwin = newwin(8+numchoices, maxchoicewidth + 10, (LINES-(6+numchoices))/2, (COLS-(maxchoicewidth+10))/2);
CURbox(cur, tempwin, 8+numchoices, 10 + maxchoicewidth);
/*** Add the window title ***/
if (Wintitle != NULL) {
wmove(tempwin, 0,(maxchoicewidth+10 -2 - strlen(Wintitle))/2);
wstandout(tempwin);
waddstr(tempwin, Wintitle);
wstandend(tempwin);
}
/*** Add the choices to the screen ***/
for (i=0; i<numchoices; i++) {
wmove(tempwin, 2+i,3);
wprintw(tempwin, "%d", i+1);
wprintw(tempwin, ". %s", choices[i]);
;
}
/** Add the keystroke methods **/
wmove(tempwin, 5+numchoices, 3);
wprintw(tempwin, "[Cancel ^G] [Choose 1-%d]", numchoices);
/** Add the prompt **/
wmove(tempwin, 3+numchoices, 3);
wprintw(tempwin, "%s: ", prompt);
wrefresh(tempwin);
while (1) {
i = CURwgetch(cur, tempwin);
wrefresh(tempwin);
if (i == '\007') {
delwin(tempwin);
return(-1);
}
if (i < '1' || i > ('0'+numchoices))
CURBeep(cur);
else {
delwin(tempwin);
return(i-'1');
}
}
}
/********************** Cruft for VMS follows ****************************/
#ifdef VMS
#include descrip
#include iodef
#include ssdef
#include ttdef
#include tt2def
static $DESCRIPTOR (term_name, "SYS$INPUT:");
static $DESCRIPTOR (ctrlc_message, "{control-C}");
struct char_buffer_type { unsigned short int dummy;
unsigned short int size;
unsigned long int tchars;
unsigned long int tchars2; } oldbuf, newbuf;
short term_chan;
static int first = 1;
static int in_pos, in_len;
static volatile int interrupt_flag;
static long outband_mask[2] = { 0, 16 };
static unsigned char buffer[20];
int CURinterrupt ( clear_flag )
int clear_flag;
{
if ( interrupt_flag ) {
int temp = interrupt_flag;
if ( clear_flag ) interrupt_flag = 0;
return temp;
}
return 0;
}
static int control_c_ast ( )
{
int status;
short iosb[4];
interrupt_flag = 1;
status = sys$qiow ( 0, term_chan, IO$_SETMODE|IO$M_CTRLCAST,
&iosb, 0, 0,
&control_c_ast, &outband_mask, 0, 0, 0, 0 );
}
/*
* Define local replacement for wgetch that returns the characters without
* having to set the terminal /pasthru, which screws up control-Y processing.
*/
static int w_getch ( win )
int win;
{
int status;
unsigned short iosb[4];
if ( in_pos < in_len ) { return (buffer[in_pos++]); }
status = sys$qiow ( 0, term_chan, IO$_READVBLK|IO$M_NOECHO|IO$M_NOFILTR,
&iosb, 0, 0, &buffer, 1, 0, 0, 0, 0 );
if ( (status&1) == 1 ) status = iosb[0];
if ( status == SS$_PARTESCAPE ) {
/* escape sequence in progress, fake a successful read */
status = 1;
}
if ( (status&1) != 1 ) exit ( status );
in_pos = 1;
in_len = iosb[1] + iosb[3];
return ( buffer[0] );
}
void
setterm_pas()
{
int status;
short iosb[4];
sys$assign(&term_name,&term_chan,0,0);
if(first==1) sys$qiow(0,term_chan,IO$_SENSEMODE,0,0,0,&oldbuf,12,0,0,0,0);
first = 0;
newbuf = oldbuf;
/* set initial control-C AST on channel */
in_pos = 0; in_len = 0;
interrupt_flag = 0;
status = sys$qiow ( 0, term_chan, IO$_SETMODE|IO$M_CTRLCAST,
&iosb, 0, 0,
&control_c_ast, &outband_mask, 0, 0, 0, 0 );
}
void
resetterm()
{
sys$qiow(0,term_chan,IO$_SETMODE,0,0,0,&oldbuf,12,0,0,0,0);
sys$dassgn(term_chan);
}
/* VMS doesn't have termcap. Unfortunately, the code in this */
/* module uses termcap just a little bit (it really shouldn't) */
/* rather than doing everything through curses */
/* The following simulates tputs, but does not support padding */
tputs(cp, affcnt, outc)
register char *cp;
int affcnt;
int (*outc)();
{
while (*cp)
outc(*(cp++));
}
#endif /* VMS */